﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.EnterpriseServices;
using System.Runtime.InteropServices;

namespace Rfid
{
    [ComVisible(true)]
    [Guid("6F463014-95F6-4D32-A0BB-CC10C48BFC7E")]
    public interface rfidControlInterface
    {
        [DispId(1)]
        uint GetLibVer();/*测试用，取得调用dll 库的版本号*/

        [DispId(2)]
        int ConnectDevice();/*连接设备*/

        [DispId(3)]
        int SeekCard();/*寻卡*/

        [DispId(4)]
        string ReadBlock(int sector, int block, string key);/*读卡(读取一个块)操作*/

        [DispId(5)]
        int WriteBlock(int sector, int block, string Msg, string key);/*写卡*/
    }

    [ComVisible(true)]
    [Guid("127C62DB-2CBA-45CD-AF23-BE8AE6518B83"),
    ClassInterface(ClassInterfaceType.None)]
    public class rfidControlImpl : ServicedComponent,rfidControlInterface
    {
        static bool bConnectedDevice;/*是否连接上设备*/

        /* 取得MasterRD.dll 的版本号，作当初编写程序的测试用*/
        public uint GetLibVer()
        {
            uint ver = 0;
            lib_ver(ref ver);/* 调用 MasterRD.dll中的 lib_ver(int ref ver)方法*/
            return ver;
        }

        static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

        /*把一个无符号整数转化为十六进制数（ASCII码）*/
        public static byte GetHexBitsValue(byte ch)
        {   
            byte sz = 0;
            if (ch <= '9' && ch >= '0')
                sz = (byte)(ch - 0x30);
            if (ch <= 'F' && ch >= 'A')
                sz = (byte)(ch - 0x37);
            if (ch <= 'f' && ch >= 'a')
                sz = (byte)(ch - 0x57);

            return sz;
        }
   
        /* 把一个字符数组转化为十六进制字符的字符串数组*/
        public static string ToHexString(byte[] bytes)
        {
            char[] chars = new char[bytes.Length * 2];

            for (int i = 0; i < bytes.Length; i++)
            {
                int b = bytes[i];
                chars[i * 2] = hexDigits[b >> 4];
                chars[i * 2 + 1] = hexDigits[b & 0xF];
            }

            return new string(chars);
        }

       /* 把一个十六进制的字符（字符串类型）转化为一个字节数组*/ 
        public static byte[] ToDigitsBytes(string theHex)
        {
            byte[] bytes = new byte[theHex.Length / 2 + (((theHex.Length % 2) > 0) ? 1 : 0)];
            for (int i = 0; i < bytes.Length; i++)
            {
                char lowbits = theHex[i * 2];
                char highbits;

                if ((i * 2 + 1) < theHex.Length)
                    highbits = theHex[i * 2 + 1];
                else
                    highbits = '0';

                int a = (int)GetHexBitsValue((byte)lowbits);
                int b = (int)GetHexBitsValue((byte)highbits);
                bytes[i] = (byte)((a << 4) + b);
            }

            return bytes;
        }

        public int ConnectDevice()
        {
            /*连接设备*/
            if (!bConnectedDevice)
            {
                int port = 1;/*端口号，其实应该是1~8，让程序自动循环执行去试每个端口，直到OK为止*/
                int baud = 9600;/*比特率，设为9600*/
                int status;/* 连接读卡器的状态*/

                /* 对计算机的1~8号串口进行连接读卡器测试*/
                for (int i = 1; i < 9; i++)
                {
                    status = rf_init_com(i, baud);
                    if (0 == status)
                    {
                        /*连接成功*/
                        bConnectedDevice = true;
                        MessageBox.Show("连接设备成功!");
                        port = i;
                        return 0; // 连接读卡器成功
                    }
                    else if (0 != status && i == 8)
                    {
                        /*最后一次8号端口连接也不成功*/
                        string strError;
                        strError = "连接设备失败，请检查设备状态后重试!!";
                        bConnectedDevice = false;
                        MessageBox.Show(strError, "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return -1; // 连接读卡器失败
                    }
                }
            }
            else
            {/* 1~8号端口都不成功连接*/
                rf_ClosePort();
                bConnectedDevice = false;
                return -1;
            }
            return -1;
        }

        /*寻卡操作*/
        public int SeekCard()
        {
            short icdev = 0x0000; //设备号
            int status;//设备状态
            byte type = (byte)'A';  //mifare one 卡询卡方式为A
            byte mode = 0x52;
            ushort TagType = 0;
            byte bcnt = 0x04;   //mifare 卡都用4
            IntPtr pSnr;    //卡的序列号 response data from card, unique serial number 
            byte len = 255;
            sbyte size = 0;

            /* 检查是否正常连接读卡器*/
            if (!bConnectedDevice)
            {
                MessageBox.Show("寻卡时与设备失去连接，请重新连接设备 !", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return -1;
            }

            pSnr = Marshal.AllocHGlobal(1024);/*开辟内存用于保存卡的序列号*/

            for (int i = 0; i < 2; i++)
            {
                status = rf_antenna_sta(icdev, 0);//关闭天线
                if (status != 0)
                    continue;

                Sleep(20);
                status = rf_init_type(icdev, type);
                if (status != 0)
                    continue;

                Sleep(20);
                status = rf_antenna_sta(icdev, 1);//启动天线
                if (status != 0)
                    continue;

                Sleep(50);
                status = rf_request(icdev, mode, ref TagType);//搜寻所有的卡
                if (status != 0)
                    continue;

                status = rf_anticoll(icdev, bcnt, pSnr, ref len);//返回卡的序列号
                if (status != 0)
                    continue;

                status = rf_select(icdev, pSnr, len, ref size);//锁定一张ISO14443-3 TYPE_A 卡
                if (status != 0)
                    continue;

                byte[] szBytes = new byte[len + 1];
                string str = Marshal.PtrToStringAnsi(pSnr);

                for (int j = 0; j < len; j++)
                {
                    szBytes[j] = (byte)str[j];
                }

                MessageBox.Show("寻卡成功，卡的序列号：" + ToHexString(szBytes));// 输出卡的系列号
                return 0;
            }

            Marshal.FreeHGlobal(pSnr);
            return 1;// 没有寻到 rfid 卡
        }

         /*读卡(读取一个块)操作*/
        public string ReadBlock(int sector, int block, string key)
        {  
            string msg = "";     /*读出的信息*/
            short icdev = 0x0000;/* 读卡号设备号*/
            int status;
            byte mode = 0x60;   //密钥选择 model = 0x60: use KeyA ；model= 0x61: use KeyB

            if (!bConnectedDevice)
            {
                //MessageBox.Show("读卡：未连接设备，请新连接!!", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return "error code : -1";
            }

            IntPtr keyBuffer = Marshal.AllocHGlobal(256);//分配256字节的内存用于存放密钥

            byte[] bytesKey = ToDigitsBytes(key);/*输入密钥*/
            for (int i = 0; i < bytesKey.Length; i++)
                Marshal.WriteByte(keyBuffer, i * Marshal.SizeOf(typeof(Byte)), bytesKey[i]);

            status = rf_M1_authentication2(icdev, mode, (byte)(sector * 4), keyBuffer);//验证密钥
            Marshal.FreeHGlobal(keyBuffer);
            if (status != 0)
            {
                // MessageBox.Show("密钥不正确!!", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return "error code: 2";
            }

            IntPtr dataBuffer = Marshal.AllocHGlobal(256);//分配存储读出卡中数据的内存

            byte cLen = 0;/* 记录读出数据的长度*/
            status = rf_M1_read(icdev, (byte)((sector * 4) + block), dataBuffer, ref cLen); // 读出卡中特定一个块的数据 块的绝对地址为 (sector * 4) + block

            if (status != 0 || cLen != 16)
            {
                /* 当读卡失败或读出的数据长度不为16个字节时，判为读卡不成功*/
                // MessageBox.Show("读卡失败!!", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Marshal.FreeHGlobal(dataBuffer);
                return "error code: 3";
            }

            byte[] bytesData = new byte[16];// 以下是数据转换处理，把读出的字节数组转化成字符串类型string,再返回
            for (int j = 0; j < bytesData.Length; j++)
                bytesData[j] = Marshal.ReadByte(dataBuffer, j);

            msg = System.Text.Encoding.Default.GetString(bytesData);

            Marshal.FreeHGlobal(dataBuffer);
            return msg;
        }

        public int WriteBlock(int sector, int block, string Msg, string key)
        {   /*写入一个块大小的内容入卡*/
            short icdev = 0x0000;
            int status;
            byte mode = 0x60;
            byte adr = (byte)(block + sector * 4);   //块的绝对地址
            int i;

            if (!bConnectedDevice)
            {
                //MessageBox.Show("写卡：未连接设备，请重新连接!!", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return -1;
            }

            // 提示更改密钥工作交由java程序调用处理
            //if (block == 3)
            //{
            //    if (DialogResult.Cancel == MessageBox.Show("你将要执行更改密钥操作，请确认！", "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning))
            //        return 0; // 取消更改密钥操作，程序正常退出
            //}

            IntPtr keyBuffer = Marshal.AllocHGlobal(1024);

            byte[] bytesKey = ToDigitsBytes(key);// 输入密钥
            for (i = 0; i < bytesKey.Length; i++)
                Marshal.WriteByte(keyBuffer, i, bytesKey[i]);
            status = rf_M1_authentication2(icdev, mode, (byte)(sector * 4), keyBuffer);// 验证密钥
            Marshal.FreeHGlobal(keyBuffer);

            if (status != 0)
            {
                // MessageBox.Show("密钥不正确 !", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return 2;
            }

            byte[] bytesData = System.Text.Encoding.Default.GetBytes(Msg);// 写入信息的预处理，把string 类型的msg转化为byte[]

            IntPtr dataBuffer = Marshal.AllocHGlobal(1024);/*开辟内存用于存放写入信息*/

            for (i = 0; i < bytesData.Length; i++)
                Marshal.WriteByte(dataBuffer, i, bytesData[i]);
            status = rf_M1_write(icdev, adr, dataBuffer);   // 写卡操作

            Marshal.FreeHGlobal(dataBuffer);

            if (status != 0)
            {   //写入不成功
                // MessageBox.Show("写卡不成功 ， 请新执行 !", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return 4;
            }
            else return 0;
        }
        /*  以下是引用MasterRD.dll和MasterCom.dll内的方法，这两个dll提供对读卡器的基本操作*/
        [DllImport("kernel32.dll")]
        static extern void Sleep(int dwMilliseconds);

        [DllImport("MasterRD.dll")]
        static extern int lib_ver(ref uint pVer);


        [DllImport("MasterRD.dll")]
        static extern int rf_init_com(int port, int baud);

        [DllImport("MasterRD.dll")]
        static extern int rf_ClosePort();

        [DllImport("MasterRD.dll")]
        static extern int rf_antenna_sta(short icdev, byte mode);

        [DllImport("MasterRD.dll")]
        static extern int rf_init_type(short icdev, byte type);

        [DllImport("MasterRD.dll")]
        static extern int rf_request(short icdev, byte mode, ref ushort pTagType);

        [DllImport("MasterRD.dll")]
        static extern int rf_anticoll(short icdev, byte bcnt, IntPtr pSnr, ref byte pRLength);

        [DllImport("MasterRD.dll")]
        static extern int rf_select(short icdev, IntPtr pSnr, byte srcLen, ref sbyte Size);

        [DllImport("MasterRD.dll")]
        static extern int rf_halt(short icdev);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_authentication2(short icdev, byte mode, byte secnr, IntPtr key);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_initval(short icdev, byte adr, Int32 value);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_increment(short icdev, byte adr, Int32 value);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_decrement(short icdev, byte adr, Int32 value);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_readval(short icdev, byte adr, ref Int32 pValue);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_read(short icdev, byte adr, IntPtr pData, ref byte pLen);

        [DllImport("MasterRD.dll")]
        static extern int rf_M1_write(short icdev, byte adr, IntPtr pData);
    }
}